package com.smsc.headend.task.engine.utils;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.google.common.collect.Lists;
import com.lowagie.text.DocumentException;
import com.lowagie.text.PageSize;
import com.lowagie.text.Paragraph;
import com.lowagie.text.Table;
import com.lowagie.text.pdf.PdfPCell;
import com.lowagie.text.pdf.PdfPTable;
import com.lowagie.text.pdf.PdfWriter;
import com.lowagie.text.rtf.RtfWriter2;
import com.smsc.headend.common.utils.HttpContextUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author xiaosc
 * @date 2021/1/26 10:08
 */

@Slf4j
public class ExcelUtils {

    public static List<List<String>> head(String[] array) {
        List<List<String>> list = CollUtil.newArrayList();
        for (String s : array) {
            List<String> head = CollUtil.newArrayList();
            head.add(s);
            list.add(head);
        }
        return list;
    }

    public static List<List<Object>> dataList(List<?> list, String[] keys) {
        List<List<Object>> dataList = CollUtil.newArrayList();
        for (Object o : list) {
            List<Object> data = CollUtil.newArrayList();
            for (String key : keys) {
                Object value = BeanUtil.getFieldValue(o, key);
                if (value == null) {
                    data.add("");
                } else {
                    data.add(value.toString());
                }
            }
            dataList.add(data);
        }
        return dataList;
    }

    public static void writeExcel(HttpServletResponse response, String fileName, List<?> list, String[] titles, String[] keys) throws IOException {
        response.reset();
        fileName = URLEncoder.encode(fileName, "UTF-8");
        response.setHeader("Content-Disposition", "attachment; filename=" + fileName + ".xlsx");
        response.setContentType("application/octet-stream; charset=UTF-8");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin());
        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        EasyExcel.write(response.getOutputStream()).head(head(titles))
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .registerWriteHandler(getStyleStrategy())
                .autoCloseStream(true).sheet()
                .doWrite(dataList(list, keys));
    }

    private static void exportXml(ServletOutputStream outputStream, String[] heads, List<List<Object>> dataList) {
        Document document = DocumentHelper.createDocument();
        XMLWriter output = null;
        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding("UTF-8");
        try {
            output = new XMLWriter(outputStream, format);
        } catch (Exception e) {
            e.printStackTrace();
        }
        Element root = document.getRootElement();
        if( root == null) {
            //root = document.addElement(this.etable.getTitle());
            root = document.addElement("root");
        }
        Element secondElm = root.addElement("rows");
        Element thirdElm = null;
        Element fourthElm = null;
        for (List row : dataList) {
            int k=0;
            boolean rowDelFlag = true;
            thirdElm = secondElm.addElement("row");
            for(Object cell: row) {
                boolean cellStrEmpty = false;
                String cellStr = cell.toString();
                if(cellStr == null || "".equals(cellStr.trim())) {
                    cellStrEmpty = true;
                }else {
                    rowDelFlag = false;
                }
                if(!cellStrEmpty && (cellStr.equalsIgnoreCase("root"))) {
                    secondElm.remove(thirdElm);
                    break;
                }else if(!cellStrEmpty && cellStr.equalsIgnoreCase(heads[0])) {
                    secondElm.remove(thirdElm);
                    break;
                }else {
                    String title = heads[k];
//                    if(title==null || "".equals(title)) {
//                        title = "cell";
//                    }else {
//                        title = title.replaceAll(" ", "").replaceAll("/", "");//不能有空格，否则浏览器打不开
//                        if(title.contains(":")) {
//                            thirdElm.addNamespace(title.split(":")[0], "1");
//                        }
//                    }
                    fourthElm = thirdElm.addElement("cell").addAttribute("title",title);
                    fourthElm.setText(cellStr);
                    k++;
                }
            }
            if(rowDelFlag) secondElm.remove(thirdElm);
        }

        try {
            output.write(document);
            output.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                output.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    private static void exportCsv(ServletOutputStream outputStream, String[] titles, List<List<Object>> dataList) {
        BufferedWriter output = null;
        StringBuilder buffer = new StringBuilder();
        for (String title : titles) {
            buffer.append(title+",");
        }
        buffer = new StringBuilder(buffer.substring(0, buffer.lastIndexOf(",")) + "\n");
        for (List row : dataList) {
            StringBuilder buffer2 = new StringBuilder();
            for (Object cell : row) {
                buffer2.append(cell.toString().replaceAll("\n", " ")+",");
            }
            buffer.append(buffer2.substring(0, buffer2.lastIndexOf(",")) + "\n");
        }
        try {
            output = new BufferedWriter(new OutputStreamWriter(outputStream));
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            output.write(buffer.toString());
            output.flush();
        } catch (Exception e) {
        } finally {
            try {
                output.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    public static void write(HttpServletResponse response, String fileName, List<?> list, String[] titles, String[] keys, String fileType) throws IOException {
        response.reset();
        fileName = URLEncoder.encode(fileName, "UTF-8");
        response.setHeader("Content-Disposition", "attachment; filename=" + fileName + "." + fileType);
        response.setContentType("application/octet-stream; charset=UTF-8");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin());
        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        switch (fileType){
            case "xlsx":
                EasyExcel.write(response.getOutputStream()).head(head(titles))
                        .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                        .registerWriteHandler(getStyleStrategy())
                        .autoCloseStream(true).sheet()
                        .doWrite(dataList(list, keys));
                break;
            case "csv":
                exportCsv(response.getOutputStream(),titles,dataList(list, keys));
                break;
            case "xml":
                exportXml(response.getOutputStream(),titles,dataList(list, keys));
                break;
            case "pdf":
                exportPdf(response.getOutputStream(),titles,dataList(list, keys));
                break;
            case "doc":
                exportDoc(response.getOutputStream(),titles,dataList(list, keys));
                break;
        }

    }

    public static void writeReport(String remoteFileGenPath, String typeName, String fileName, List<?> list, String[] titles, String[] keys, String fileType) throws IOException {
        String fullPath;
        if (!remoteFileGenPath.endsWith(File.separator)) {
            fullPath = remoteFileGenPath + File.separator + typeName + File.separator;
        } else {
            fullPath = remoteFileGenPath  + typeName + File.separator;
        }
        log.info("remoteFileGenPath {} , type name {}, file name {}, fullPath {}", remoteFileGenPath, typeName, fileName, remoteFileGenPath);
        if(!FileUtil.exist(fullPath)) {
            FileUtil.mkdir(fullPath);
        }
        switch (fileType){
            case "reportDownload":
                String fileFullName = fullPath + fileName + ".xlsx";
                if (list.size() > 500000) {
                    // 大于 500000 分成多个sheet写入
                    ExcelWriter excelWriter = EasyExcel.write(fileFullName).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                            .registerWriteHandler(getStyleStrategy()).build();
                    int i = 0;
                    List<? extends List<?>> subList = Lists.partition(list,500000);
                    for (List<?> itemList : subList) {
                        int num = i+1;
                        WriteSheet writeSheet = EasyExcel.writerSheet(num, "Sheet" + num).head(head(titles)).build();
                        excelWriter.write(dataList(itemList, keys), writeSheet);
                    }
                    excelWriter.finish();
                } else {
                    EasyExcel.write(fileFullName).head(head(titles))
                            .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                            .registerWriteHandler(getStyleStrategy())
                            .autoCloseStream(true).sheet()
                            .doWrite(dataList(list, keys));
                }
                break;
            default:
                log.error("no implementation currently");
        }
    }

    private static void exportPdf(ServletOutputStream outputStream, String[] titles, List<List<Object>> dataList) {
        com.lowagie.text.Document doc = null;
        if(titles.length > 40) {
            doc = new com.lowagie.text.Document(PageSize.A0.rotate(),0,0,50,0);
        } else if(titles.length > 30 && titles.length <= 40) {
            doc = new com.lowagie.text.Document(PageSize.A1.rotate(),0,0,50,0);
        } else if(titles.length > 20 && titles.length <= 30) {
            doc = new com.lowagie.text.Document(PageSize.A2.rotate(),0,0,50,0);
        } else if(titles.length > 10 && titles.length <= 00) {
            doc = new com.lowagie.text.Document(PageSize.A3.rotate(),0,0,50,0);
        } else {
            doc = new com.lowagie.text.Document(PageSize.A4.rotate(),0,0,50,0);
        }
        try {
            PdfWriter writer = PdfWriter.getInstance(doc, outputStream);
            doc.open();
            for (int i = 0; i < 1; i++) {
                PdfPTable table = new PdfPTable(titles.length);
                for(String title:titles) {
                    String cellValue = title;
                    PdfPCell cell = new PdfPCell(new Paragraph(cellValue));// 单元格
                    // 其中1为居中对齐，2为右对齐，3为左对齐
                    cell.setVerticalAlignment(1);
                    table.addCell(cell);
                }
                for (List row : dataList) {
                    if (row == null) {
                        continue;
                    }
                    for (Object col : row) {
                        if (col == null) {
                            continue;
                        }
                        String cellValue = col.toString();
                        PdfPCell cell = null;
                        cell = new PdfPCell(new Paragraph(cellValue));// 单元格
                        // 其中1为居中对齐，2为右对齐，3为左对齐
                        cell.setVerticalAlignment(1);
                        //cell.setHorizontalAlignment(alignment - 1);
                        //cell.setWidth(100);
                        table.addCell(cell);
                    }
                }
                doc.add(table);
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        } finally {
            try {
                doc.close();
                outputStream.flush();
                outputStream.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    private static void exportDoc(ServletOutputStream outputStream, String[] titles, List<List<Object>> dataList) {
        com.lowagie.text.Document doc = new com.lowagie.text.Document(PageSize.A4.rotate(),0,0,50,0);
        float fontSize = 10.0f;
        if(titles.length > 40) {
            fontSize = 2.0f;
        } else if(titles.length > 30 && titles.length <= 40) {
            fontSize = 4.0f;
        } else if(titles.length > 20 && titles.length <= 30) {
            fontSize = 6.0f;
        } else if(titles.length > 10 && titles.length <= 00) {
            fontSize = 8.0f;
        }
        try {
            RtfWriter2 writer = RtfWriter2.getInstance(doc, outputStream);
            doc.open();
            for (int i = 0; i < 1; i++) {
                Table table = new Table(titles.length,dataList.size());
                for(String title:titles) {
                    String cellValue = title;
                    com.lowagie.text.Font font = com.lowagie.text.FontFactory.getFont("Courier","Cp1252", fontSize);
                    com.lowagie.text.Cell cell = new com.lowagie.text.Cell(new Paragraph(cellValue,font));// 单元格
                    // 其中1为居中对齐，2为右对齐，3为左对齐
                    cell.setVerticalAlignment(1);
                    table.addCell(cell);
                }
                for (List row : dataList) {
                    if (row == null) {
                        continue;
                    }
                    for (Object col : row) {
                        if (col == null) {
                            continue;
                        }
                        String cellValue = col.toString();
                        com.lowagie.text.Cell cell = null;
                        com.lowagie.text.Font font = com.lowagie.text.FontFactory.getFont("Courier","Cp1252", fontSize);
                        cell = new com.lowagie.text.Cell(new Paragraph(cellValue, font));// 单元格
                        // 其中1为居中对齐，2为右对齐，3为左对齐
                        cell.setVerticalAlignment(1);
                        //cell.setHorizontalAlignment(alignment - 1);
                        //cell.setWidth(100);
                        table.addCell(cell);
                    }
                }
                doc.add(table);
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        } finally {
            try {
                doc.close();
                outputStream.flush();
                outputStream.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    public static HorizontalCellStyleStrategy getStyleStrategy() {
        // 头的策略
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        // 设置对齐
        // headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
        // 背景色, 设置为白色，也是默认颜色
        // headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
        // 字体
        WriteFont headWriteFont = new WriteFont();
        headWriteFont.setFontHeightInPoints((short) 12);
        headWriteCellStyle.setWriteFont(headWriteFont);
        // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
        return new HorizontalCellStyleStrategy(headWriteCellStyle, new ArrayList<>());
    }

    public static ServletOutputStream setResponseHeader(HttpServletResponse response, String fileName) throws IOException {
        response.reset();
        response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xlsx");
        response.setContentType("application/octet-stream; charset=UTF-8");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin());
        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        return response.getOutputStream();
    }
}
